package com.lambda.security.web.verify.service.sms.store;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lambda.autoconfig.SecurityProperties;
import com.lambda.security.web.verify.service.sms.model.SmsVerifyCode;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.text.MessageFormat;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.NonNull;

@SuppressFBWarnings(
        value = {"EI_EXPOSE_REP2"},
        justification = "springboot properties")
public class RedisSmsVerifyCodeStore implements SmsVerifyCodeStore<String> {
    private final Gson gson = new Gson();
    private static final String PREFIX_KEY = "Authorization:login:smsVerify";
    private final SecurityProperties.SmsLogin smsLogin;
    private final StringRedisTemplate stringRedisTemplate;

    public RedisSmsVerifyCodeStore(SecurityProperties.SmsLogin smsLogin, StringRedisTemplate stringRedisTemplate) {
        this.smsLogin = smsLogin;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public long getPeriod() {
        return smsLogin.getValidMinutes();
    }

    @Override
    public long getInterval() {
        return smsLogin.getResendSeconds();
    }

    @Override
    public String generate(String key) {
        String code = Integer.toString(RandomUtil.randomInt(1000, 9999));
        stringRedisTemplate
                .opsForValue()
                .set(getCommonKey(key), gson.toJson(new SmsVerifyCode<>(code)), getPeriod(), TimeUnit.MINUTES);
        return code;
    }

    @Override
    public boolean verify(@NonNull String key, @NonNull String code) {
        SmsVerifyCode<String> smsVerifyCode = get(key);
        boolean result = code.equals(smsVerifyCode.getCode());
        if (result) {
            stringRedisTemplate.delete(getCommonKey(key));
        }
        return result;
    }

    @Override
    public SmsVerifyCode<String> get(String key) {
        String cache = stringRedisTemplate.opsForValue().get(getCommonKey(key));
        if (StrUtil.isEmpty(cache)) {
            return null;
        }
        return gson.fromJson(cache, new SmsVerifyCodeTypeToken().getType());
    }

    private String getCommonKey(String key) {
        return MessageFormat.format("{0}:{1}", PREFIX_KEY, key);
    }

    private static class SmsVerifyCodeTypeToken extends TypeToken<SmsVerifyCode<String>> {}
}
